home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / libs / knowhow4 / fill.cpp < prev    next >
C/C++ Source or Header  |  1994-10-10  |  9KB  |  320 lines

  1. /*  Fill functions, (C) as the part of KNOW-HOW.DRAW, HOTKEY DRAW,
  2.     HOTKEY PLOT and HOTKEY OBJECT DRAW packages.
  3.     This file contains floodfill function for BGI
  4.     library. The area may be represented as two-dimentional vessel, which
  5.     we fill with water, in the absence of athmosphere.
  6. */
  7.  
  8. #include <stdlib.h>
  9. #include <conio.h>
  10. #include <mem.h>
  11.  
  12. #include "pixel.h"
  13. #include "graphpp.h"
  14.  
  15. enum { DN, LEFT, RIGHT, L_DN, R_DN, UP, L_UP, R_UP, NO };
  16.  
  17. rect level[640];   // there are <= 640 elements in this realization,
  18.            // the VGA horiz. dimention. Using left-to-right filling
  19.            // we may use 480 elements
  20. char flag;         // draw_line (1) or go_local (0)
  21. int used;          // number of elements in level[]
  22. int local;         // is it local min ?
  23. rect work;         // used to avoid copying
  24. rect bound;        // outline of the area to fill, used to avoid copying
  25. int start_color;   // color in the start pixel, used to avoid copying
  26. int attr, bak;     // colors, used to avoid additional copying in put_pixel()
  27.            // calls
  28. char* fill;        // fill pattern
  29. /////////////////////////////
  30. inline int get_pixel(loc p)                               // is this pixel
  31.     {                                                     // have color ==
  32.     if(getpixel(p) != start_color || !bound.contains(p))  // start_color,
  33.     return 0;                                         // and is it inside
  34.     return 1;                                             // of bound (work
  35.     }                                                     // area
  36.  
  37. inline int get_pixel(int x, int y) { return get_pixel(loc(x, y)); }
  38. ////////////////////////////
  39. inline void putPixel(loc pos)
  40.     {
  41.     if(!global_i[8])
  42.     put_pixel(pos.X, pos.Y, global_i[9]);
  43.     else
  44.     put_pixel_error_prop(pos.X, pos.Y, global_i[9], 48);
  45.     }
  46. ////////////////////////////
  47. int inside(loc p)                 // is there any line under current pixel ?
  48.     {
  49.     for(int i = 0; i < used; i++)
  50.     {
  51.     if(p.Y > level[i].origin.Y - 1)
  52.         continue;
  53.     else if(p.Y < level[i].origin.Y - 1)
  54.         return 0;
  55.     if(p.X <= level[i].corner.X && p.X >= level[i].origin.X)
  56.         return 1;
  57.     }
  58.     return 0;
  59.     }
  60. ///////////////////////
  61. int go_local(int left = 1)     // go to the local minimum under the current
  62.     {                          // pixel. "left" is used to block left moving
  63.     int i = 1;                 // if we use the same start and fill colors
  64.     loc pos = getCP();         // and can not begin from step down
  65.     while(1)
  66.     {
  67.     if(get_pixel(pos.X, pos.Y + 1) && !inside(pos))
  68.         { moveto(pos = loc(pos.X, pos.Y + 1)); i = 0; } // left = 1; }
  69.     else if(left && get_pixel(pos.X - 1, pos.Y))
  70.         { moveto(pos = loc(pos.X - 1, pos.Y)); i = 0; }
  71.     else break;
  72.     }
  73.     local = 1;
  74.     return i;
  75.     }
  76. ////////////////////////
  77. rect get_line()                          // return the line under current
  78.     {                                    // pixel
  79.     loc pos = getCP();
  80.     rect line_below = rect(pos, pos);
  81.     for(int i = 0; i <= used; i++)
  82.     {
  83.     if(level[i].corner.Y == pos.Y && level[i].contains(pos))
  84.         {
  85.         line_below = level[i];
  86.         break;
  87.         }
  88.     }
  89.     return line_below;
  90.     }
  91. ///////////////////////
  92. void remove(rect r)                     // remove line from array
  93.     {
  94.     for(int i = 0; i <= used; i++)
  95.     {
  96.     if(level[i].origin.Y == r.origin.Y
  97.        && level[i].origin.X == r.origin.X)
  98.         {
  99.         for(; i <= used; i++)
  100.         level[i] = level[i + 1];
  101.         used--;
  102.         break;
  103.         }
  104.     }
  105.     }
  106. ///////////////////////
  107. void add(rect r)                 // add line to array. Lines are sorted
  108.     {                            // by Y, then by X
  109.     int i;
  110.     for(i = 0; i <= used; i++)
  111.     {
  112.     if(level[i].origin.Y == r.origin.Y && level[i].origin.X > r.origin.X)
  113.         break;
  114.     else if(level[i].origin.Y > r.origin.Y)
  115.         break;
  116.     }
  117.     for(int j = used; j >= i; j--)
  118.     level[j + 1] = level[j];
  119.     if(i > used)
  120.     i--;
  121.     level[i] = r;
  122.     work = r;
  123.     used++;
  124.     }
  125. ///////////////////////////
  126. void draw_line()          // draws line with current colors and pattern
  127.     {
  128.     flag = 1;
  129.     loc pos = getCP();
  130.     rect line_below = get_line();          // if we draw line above any other
  131.     rect new_rect;                         // contains new line
  132.     remove(line_below);
  133.     loc p = getCP();
  134.     if(!local)                            // it is not local minimum
  135.     {
  136.     moveto(loc(line_below.origin.X, line_below.origin.Y - 1));   // go up
  137.     while(1)
  138.         {
  139.         p = getCP();
  140.         if((!get_pixel(p))               // no place above leftmost pixel
  141.         && line_below.corner.X >= p.X)       // and we can move right
  142.         {
  143.         if(line_below.corner.X == p.X)       // if it is the end of
  144.             {                                // line_below
  145.             if(!used)                        // if no ways from this
  146.             flag = 0;                    // point
  147.             break;
  148.             }
  149.         else moveto(loc(p.X + 1, p.Y));
  150.         }
  151.         else break;
  152.         }
  153.  
  154.     while(1)
  155.         {
  156.         p = getCP();
  157.         if((get_pixel(p.X - 1, p.Y))                  // left, but not dn
  158.         && get_pixel(p)
  159.         && (!get_pixel(p.X, p.Y + 1)
  160.             || p.X >= line_below.origin.X)        // or we are above
  161.         && !inside(loc(p.X - 1, p.Y - 1)))        // and no intersection
  162.         moveto(p.X - 1, p.Y);                     // with other lines
  163.         else
  164.         {
  165.         if(line_below.origin.X > p.X              // we can go_local
  166.             && get_pixel(p.X, p.Y + 1))
  167.             flag = 0;
  168.         break;
  169.         }
  170.         }
  171.     }
  172.     int mark = 0;
  173.     if(get_pixel(p))            // first pixel of line
  174.     {
  175.     putPixel(p);
  176.     mark = 1;               // mark that at least one pixel drawn
  177.     }
  178.     new_rect = rect(p, p);
  179.  
  180.     int disable = 1;           // first time impossible to put pixel
  181.  
  182.     while(1)
  183.     {
  184.     p = loc(p.X + 1, p.Y);
  185.     if( mark
  186.         && get_pixel(p)
  187.         && (p.X <= line_below.corner.X
  188.         || (!get_pixel(p.X, p.Y + 1)
  189.             || inside(p))))
  190.         {
  191.         putPixel(p);        // draw line in cycle
  192.         if(disable)
  193.         new_rect.corner = p;
  194.         else
  195.         new_rect.origin = p;
  196.         disable = 1;
  197.         }
  198.     else
  199.         {
  200.         if(disable && mark)          // all with this line
  201.         add(new_rect);
  202.         if(get_pixel(p.X, p.Y + 1)   // we can go_local
  203.         && get_pixel(p))
  204.         flag = 0;
  205.         if(p.X >= line_below.corner.X)
  206.         break;
  207.         else
  208.         new_rect = rect(p, loc(line_below.corner.X,
  209.                        line_below.corner.Y - 1));
  210.         disable = 0;
  211.         }
  212.     moveto(p);
  213.     }
  214.     local = 0;
  215.     }
  216. ////////////////////////
  217. void dump_levels()                          // simplify the level[]
  218.     {
  219.     for(int i = 0; i < used; i++)
  220.     for(int j = i + 1; j < used; j++)
  221.         {
  222.         if(level[i].origin.X - 1 == level[j].corner.X
  223.            && level[i].origin.Y == level[j].origin.Y)
  224.            {
  225.            level[i].origin.X = level[j].origin.X;
  226.            remove(level[j]);
  227.            }
  228.         if(level[i].corner.X + 1 == level[j].origin.X
  229.            && level[i].origin.Y == level[j].origin.Y)
  230.            {
  231.            level[i].corner.X = level[j].corner.X;
  232.            remove(level[j]);
  233.            }
  234.  
  235.         if(level[i].corner.X >= level[j].origin.X
  236.            && level[i].origin.X <= level[j].corner.X
  237.            && level[i].origin.Y == level[j].origin.Y - 1)
  238.         {
  239.         if(level[i].origin.X <= level[j].origin.X)
  240.             level[j].origin.X = level[i].corner.X;
  241.         else
  242.             level[j].corner.X = level[i].origin.X;
  243.         if(level[j].origin.X >= level[j].corner.X)
  244.             remove(level[j]);
  245.         }
  246.         }
  247.     }
  248. ////////////////////////
  249. void fill_cell()           // fill before it is possible to go_local
  250.     {
  251.     while(flag && used && !kbhit())
  252.     {
  253.     loc pos = getCP();
  254.  
  255.     if(pos.Y == 75)
  256.         pos.Y = 75;
  257.  
  258.     moveto(level[used - 1].corner);
  259.     draw_line();
  260.     dump_levels();
  261.     }
  262.     if(kbhit())
  263.     for(int i = 0; i < 640; i++)
  264.         level[i] = rect(0, 0, 0, 0);
  265.     }
  266. ////////////////////////
  267. void fill_area(loc from, int a, int b, char* f,
  268.            rect r = rect(0, 0, getmaxx(), getmaxy()))
  269.     {
  270.     memset(level, 0, 640 * sizeof(rect));
  271.     if(!r.contains(from))
  272.     return;
  273.     flag = 1;
  274.     moveto(from);
  275.     start_color = getpixel(from);
  276.     attr = a; bak = b; bound = r; fill = f;
  277.  
  278.     go_local();          // go to start position
  279.     draw_line();         // draw the first line and add first line to level[]
  280.  
  281.     while(1)
  282.     {
  283.     if(flag)
  284.         fill_cell();
  285.     flag = 1;
  286.     if(!used)
  287.         return;
  288.     moveto(work.origin);
  289.     if(go_local())     // left local min
  290.         {
  291.         moveto(work.corner.X + 1, work.corner.Y);
  292.         if(go_local(0))    // right local min
  293.         return;
  294.         }
  295.     draw_line();
  296.     }
  297.     }
  298. ////////////////////////
  299. /*
  300. void main()
  301.     {
  302.     int gdriver = DETECT, gmode;
  303.     initgraph(&gdriver, &gmode, "..\\BGI");
  304.  
  305.     flag = 0;
  306.     used = 0;
  307.  
  308.     circle(120, 120, 100);
  309.     line(80, 80, 100, 100);
  310.     line(100, 100, 120, 100);
  311.     line(120, 100, 140, 75);
  312.  
  313.     loc from(125, 125);
  314. //    char fill[] = { 255, 255, 255, 255, 255, 255, 255, 254 };
  315.     char fill_pattern[] = { 255, 55, 25, 5, 1, 215, 155, 15 };
  316.     int attr = GREEN;
  317.     int bak = BLACK;
  318.     fill_area(from, attr, bak, fill_pattern); //, r);
  319.     }
  320. */